package cn.xshi.route.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.xshi.common.base.BaseResult;
import cn.xshi.common.base.BaseService;
import cn.xshi.common.cache.redis.RedisUtil;
import cn.xshi.common.constant.CacheConstant;
import cn.xshi.common.util.JsonUtil;
import cn.xshi.route.dao.DynamicRouteDao;
import cn.xshi.route.model.DynamicRoute;
import cn.xshi.route.publisher.GatewayChannelUtil;
import cn.xshi.route.publisher.GatewayNettyUtil;
import cn.xshi.route.service.DynamicRouteService;
import cn.xshi.route.vo.ChannelEntity;
import cn.xshi.route.vo.RequestInfo;
import cn.xshi.route.vo.RouteEntity;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.*;
/**
 * @Desc 路由信息
 * @Author 邓纯杰
 * @CreateTime 2012-12-12 12:12:12
 */
@Service
@Slf4j
public class DynamicRouteServiceImpl extends BaseService implements DynamicRouteService {

	@Resource
	private DynamicRouteDao dynamicRouteDao;

	@Resource
	private RedisUtil redisUtil;

	@Resource
    GatewayChannelUtil gatewayChannelUtil;

	@Resource
    GatewayNettyUtil gatewayNettyUtil;

	@Value("${jehc.route.clientId:GatewayRoteId}")
	private String clientId;//客户端id（每个服务对应一个客户端唯一id）

	@Value("${jehc.route.clientGroupId:GatewayGroupId}")
	private String clientGroupId;//组Id（可以存多个服务共享一个组Id）

	/**
	 * 查询列表
	 * @param condition
	 * @return
	 */
	public List<DynamicRoute> getDynamicRouteListByCondition(Map<String, Object> condition){
		return dynamicRouteDao.getDynamicRouteListByCondition(condition);
	}

	/**
	 * 查询对象
	 * @param id
	 * @return
	 */
	public DynamicRoute getDynamicRouteById(String id){
		return dynamicRouteDao.getDynamicRouteById(id);
	}

	/**
	 * 添加
	 * @param dynamicRoute
	 * @return
	 */
	public int addDynamicRoute(DynamicRoute dynamicRoute){
		dynamicRoute.setId(toUUID());
		dynamicRoute.setCreateTime(getDate());
		dynamicRoute.setCreateId(getCurrentAccountId());
		int i = dynamicRouteDao.addDynamicRoute(dynamicRoute);
		if(0 == dynamicRoute.getStatus()){//如果启用状态则发通知
			if(i>0){
				sync(dynamicRoute);
				notifyGateway(dynamicRoute.getId(),"add");//通知网关更新路由
			}
		}
		return i;
	}

	/**
	 * 修改
	 * @param dynamicRoute
	 * @return
	 */
	public int updateDynamicRoute(DynamicRoute dynamicRoute){
		dynamicRoute.setUpdateTime(getDate());
		dynamicRoute.setUpdateId(getCurrentAccountId());
		int i = dynamicRouteDao.updateDynamicRoute(dynamicRoute);
		if(i > 0){
			sync(dynamicRoute);
			notifyGateway(dynamicRoute.getId(),"update");//通知网关更新路由
		}
		return i;
	}

	/**
	 * 删除
	 * @param condition
	 * @return
	 */
	public int delDynamicRoute(Map<String, Object> condition){
		Map<String,Object> newCondition = new HashMap<>();
		StringBuffer stringBuffer = new StringBuffer();
		List<DynamicRoute> newDynamicRouteList = new ArrayList<>();
		List<DynamicRoute> dynamicRouteList = dynamicRouteDao.getDynamicRouteListByCondition(condition);
		if(!CollectionUtil.isEmpty(dynamicRouteList)){
			for(DynamicRoute dynamicRoute : dynamicRouteList){
				boolean res = notifyGateway(dynamicRoute.getId(),"delete");//通知网关更新路由
				if(!res){
					log.warn("通知网关异常：{}",dynamicRoute);
//					throw new ExceptionUtil("通知网关异常：{}");
				}else{
					newDynamicRouteList.add(dynamicRoute);
					if(null != stringBuffer && !"".equals(stringBuffer.toString())){
						stringBuffer.append(","+dynamicRoute.getId());
					}else{
						stringBuffer.append(dynamicRoute.getId());
					}
				}
			}
		}
		int i = 0;
		if(null != stringBuffer && !"".equals(stringBuffer.toString())){
			newCondition.put("id",stringBuffer.toString().split(","));
		}
		if(CollectionUtil.isNotEmpty(newCondition)){
			i = dynamicRouteDao.delDynamicRoute(newCondition);
			if(i > 0){
				for(DynamicRoute dynamicRoute:newDynamicRouteList){
					sync(dynamicRoute);
				}
			}
		}
		return i;
	}

	/**
	 * 增量操作redis
	 * @param dynamicRoute
	 */
	private void sync(DynamicRoute dynamicRoute){
		redisUtil.hset(CacheConstant.JEHC_ROUTE, dynamicRoute.getId(),JsonUtil.toFastJson(dynamicRoute));
	}

	/**
	 * 全量同步缓存
	 */
	private void sync(){
		log.info("开始同步路由...");
		Map<String,Object> condition = new HashMap<>();
		List<DynamicRoute> dynamicRouteList = dynamicRouteDao.getDynamicRouteList(condition);
		if(!CollectionUtil.isEmpty(dynamicRouteList)){
			for(DynamicRoute dynamicRoute: dynamicRouteList){
				redisUtil.hset(CacheConstant.JEHC_ROUTE, dynamicRoute.getId(),JsonUtil.toFastJson(dynamicRoute));
			}
		}
		log.info("同步路由完毕，共计{}条数据",dynamicRouteList.size());
	}

	/**
	 * 更新状态
	 * @param dynamicRoute
	 * @return
	 */
	public int updateStatus(DynamicRoute dynamicRoute){
		dynamicRoute.setUpdateTime(getDate());
		dynamicRoute.setUpdateId(getCurrentAccountId());
		int i = dynamicRouteDao.updateStatus(dynamicRoute);
		DynamicRoute route = dynamicRouteDao.getDynamicRouteById(dynamicRoute.getId());
		route.setStatus(dynamicRoute.getStatus());
		sync(route);
		if(dynamicRoute.getStatus() == 0){
			notifyGateway(dynamicRoute.getId(),"add");//通知网关更新路由
		}
		if(dynamicRoute.getStatus() == 1){
			notifyGateway(dynamicRoute.getId(),"delete");//通知网关更新路由
		}
		return i;
	}

	/**
	 * 通知网关
	 * @param id
	 * @param method
	 * @return
	 */
	private Boolean notifyGateway(String id,String method){
		List<ChannelEntity> channelEntities = gatewayChannelUtil.get(clientGroupId);
		boolean res = false;
		if(CollectionUtil.isNotEmpty(channelEntities)){
			RouteEntity routeEntity = new RouteEntity(id,method);
			res = send(channelEntities,routeEntity);
		}
		return res;
	}

	/**
	 * 执行发送
	 * @param channelEntities
	 * @param routeEntity
	 */
	private Boolean send(List<ChannelEntity> channelEntities,RouteEntity routeEntity){
		boolean res = true;
		try {
			Random random = new Random();
			int size = random.nextInt(channelEntities.size());
			ChannelEntity channelEntity = channelEntities.get(size);
			RequestInfo requestInfo = new RequestInfo();

//			//增加测试
//			List<String> list = new ArrayList<>();
//			for(int i = 0; i < 100000; i++){
//				list.add("毕业生穿校服回母校悄悄看老师!!");
//			}
//			requestInfo.setObj(list);

			requestInfo.setData(routeEntity);
			channelEntity.setRequestInfo(requestInfo);
			res = gatewayNettyUtil.sendMessage(channelEntity);
			if(res){
				log.info("通知网关路由成功，{}-{}",routeEntity,channelEntities);
			}
		}catch (Exception e){
			log.info("通知网关路由异常，{}-{}-{}",e,channelEntities,routeEntity);
			res = false;
		}
		return res;
	}

	/**
	 * 刷新全部路由
	 * @return
	 */
	public BaseResult refresh(){
		sync();
		notifyGateway(null,"refresh");//通知网关更新路由
		return BaseResult.success();
	}
}
